package org.feng.controller;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.feng.entity.SysMenu;
import org.feng.entity.SysMenuRole;
import org.feng.entity.SysUser;
import org.feng.entity.query.LoginQuery;
import org.feng.entity.result.CodeImageResult;
import org.feng.entity.result.SysMenuTreeResult;
import org.feng.service.ISysMenuRoleService;
import org.feng.service.ISysMenuService;
import org.feng.service.ISysUserService;
import org.feng.constant.RedisConstant;
import org.feng.enums.SysMenuCategoryEnum;
import org.feng.utils.TreeUtils;
import org.feng.annotation.AccessLog;
import org.feng.base.controller.BaseController;
import org.feng.base.entity.Result;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;

import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 认证
 *
 * @author : FengShuai
 * @since : 2024/6/27 9:24
 */
@RequestMapping("/system/auth")
@RestController
@Tag(name = "认证")
public class SysLoginController extends BaseController {
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private ISysMenuService sysMenuService;
    @Resource
    private ISysUserService sysUserService;

    @Value("${sa-token.aes-key}")
    private String aesKey;
    @Resource
    private ISysMenuRoleService sysMenuRoleService;

    /**
     * 用户名密码登录
     *
     * @param loginQuery 登录实体
     * @return 返回体
     */
    @PostMapping("/login")
    @AccessLog("登录")
    @Operation(summary = "登录")
    public Result<HashMap<String, String>> login(@RequestBody LoginQuery loginQuery) {
        String code = redisTemplate.opsForValue().get(RedisConstant.REDIS_LOGIN_CODE_KEY + loginQuery.getKey());
        if (StrUtil.isEmpty(code)) {
            return Result.error("验证码已过期");
        }
        if (!code.equalsIgnoreCase(loginQuery.getCode())) {
            return Result.error("验证码输入错误");
        }
        SysUser sysUser = sysUserService.getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, loginQuery.getUsername()));
        if (sysUser == null) {
            return Result.error("用户不存在");
        }
        String aesDecrypt = SaSecureUtil.aesEncrypt(aesKey, loginQuery.getPassword());
        if (!aesDecrypt.equals(sysUser.getPassword())) {
            return Result.error("密码错误");
        }
        HashMap<String, String> map = new HashMap<>();
        StpUtil.login(sysUser.getId());
        map.put("token", StpUtil.getTokenValue());
        map.put("tokenName", StpUtil.getTokenName());
        return Result.success(map);
    }

    /**
     * 获取图形验证码
     *
     * @return 图片base64
     */
    @GetMapping("/codeImage")
    @Operation(summary = "获取图形验证码")
    public Result<CodeImageResult> codeImage() {
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(200, 100, 4, 4);
        String code = captcha.getCode();
        String key = IdUtil.simpleUUID();
        redisTemplate.opsForValue().set(RedisConstant.REDIS_LOGIN_CODE_KEY + key, code, 5, TimeUnit.MINUTES);
        return Result.success(CodeImageResult.builder()
                .key(key)
                .img(captcha.getImageBase64Data())
                .build());
    }

    /**
     * 获取用户菜单权限、按钮权限
     *
     * @return menu 菜单权限 button 按钮权限
     */
    @GetMapping("/authMenu")
    @Operation(summary = "获取用户菜单权限、按钮权限")
    public Result<HashMap<String, Object>> authMenu() {
        SysUser sysUser = sysUserService.getById(StpUtil.getLoginIdAsLong());
        List<SysMenu> menuList;
        List<SysMenu> buttonList;
        if ("admin".equals(sysUser.getUsername())) {
            menuList = sysMenuService.list(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getCategory, SysMenuCategoryEnum.MENU).orderByAsc(SysMenu::getSort));
            buttonList = sysMenuService.list(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getCategory, SysMenuCategoryEnum.BUTTON).orderByAsc(SysMenu::getSort));
        } else {
            List<SysMenuRole> menuRoleList = sysMenuRoleService.list(Wrappers.<SysMenuRole>lambdaQuery().eq(SysMenuRole::getRoleId, sysUser.getRoleId()));
            List<Long> menuIdList = menuRoleList.stream().map(SysMenuRole::getMenuId).collect(Collectors.toList());
            menuList = sysMenuService.list(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getCategory, SysMenuCategoryEnum.MENU).in(SysMenu::getId, menuIdList).orderByAsc(SysMenu::getSort));
            buttonList = sysMenuService.list(Wrappers.<SysMenu>lambdaQuery().eq(SysMenu::getCategory, SysMenuCategoryEnum.BUTTON).in(SysMenu::getId, menuIdList).orderByAsc(SysMenu::getSort));
        }
        List<SysMenuTreeResult> treeResultList = toBeanList(menuList, SysMenuTreeResult.class);
        List<SysMenuTreeResult> resultList = TreeUtils.treeOut(treeResultList, SysMenuTreeResult::getId, SysMenuTreeResult::getParentId, SysMenuTreeResult::getChildren);
        List<String> authButtonList = buttonList.stream().map(SysMenu::getAuthCode).filter(Objects::nonNull).collect(Collectors.toList());
        HashMap<String, Object> map = new HashMap<>();
        map.put("menu", resultList);
        map.put("button", authButtonList);
        return Result.success(map);
    }
}
